package com.bjsdzk.collector.one2one;

import com.bjsdzk.collector.constant.Constant;
import com.bjsdzk.collector.entity.agreement.CallBackCmd;
import com.bjsdzk.collector.entity.agreement.SendCmd;
import com.bjsdzk.collector.rpc.SerialPortServiceImp;
import com.bjsdzk.collector.serviceImp.DictionariesService;
import com.bjsdzk.collector.serviceImp.ExceColleContrService;
import com.bjsdzk.collector.serviceImp.ParamsSettingService;
import com.bjsdzk.collector.utils.*;
import com.google.common.base.Joiner;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetSocket;
import io.vertx.ext.mongo.BulkOperation;
import io.vertx.ext.mongo.MongoClient;
import io.vertx.redis.RedisClient;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * @author pc
 */
public final class LnServer extends BasetVerticle {

    private static Logger logger = LoggerFactory.getLogger(com.bjsdzk.collector.one2one.LnServer.class);

    public LnServer(RedisClient redis, MongoClient mongoClient, ExceColleContrService exceColleContrService, ParamsSettingService paramsSettingService, DictionariesService dictionariesService) {
        this.redis = redis;
        this.mongoClient = mongoClient;
        this.exceColleContrService = exceColleContrService;
        this.paramsSettingService = paramsSettingService;
        this.dictionariesService = dictionariesService;
    }

    @Override
    public void start() {
        try {
            getInit();
            startCmdConsumer();
            NetServer server = getNetServer();
            server.connectHandler(netSocket -> {
                Map<String, Long> keepLiveMap = new ConcurrentHashMap<>(16);
                ConcurrentLinkedQueue<CallBackCmd> returnQueue = new ConcurrentLinkedQueue<>();
                PriorityBlockingQueue<SendCmd> sendQueue = new PriorityBlockingQueue<>();
                defaultStart(netSocket, keepLiveMap, sendQueue, returnQueue);

                if (StringUtils.equals(dtuType, Constant.DTUTYPE_11)) {
                    DetectorServer receiveServer = new DetectorServer(netSocket, keepLiveMap, sendQueue, returnQueue);
                    netSocket.handler(receiveServer);

                    long policePer = vertx.setPeriodic(1000 * 30, h -> {
                        if (lineStatus) {
                            String cmd = "0800000001AAAA42000101004002000000015555000000000000";
                            SendCmd sendCmd = new SendCmd(1, "00010100", 0, "collector", "messageId", "1", port, cmd, false, true);
                            sendCmd.setCallbackPlatForm(false);
                            sendQueue.offer(sendCmd);
                        }
                    });

                    long dataPer = vertx.setPeriodic(1000 * 60 * 15, h -> {
                        if (lineStatus) {
                            String cmd = "0800000001AAAA42000101004002000000015555000000000000";
                            SendCmd sendCmd = new SendCmd(1, "00010100", 0, "collector", "messageId", "1", port, cmd, true, true);
                            sendCmd.setCallbackPlatForm(false);
                            sendQueue.offer(sendCmd);
                        }
                    });

                    timerMap.get(netSocket.writeHandlerID()).add(policePer);
                    timerMap.get(netSocket.writeHandlerID()).add(dataPer);
                }else if(StringUtils.equals(dtuType, Constant.DTUTYPE_12)){
                    LnBreakerServer receiveServer = new LnBreakerServer(netSocket, keepLiveMap, sendQueue, returnQueue);
                    netSocket.handler(receiveServer);
                    SerialPortServiceImp serialPortServiceImp = new SerialPortServiceImp();
                    long policePer = vertx.setPeriodic(1000 * 30, h -> {
                        if(lineStatus) {
                            int cmdIdLn = (int) (Math.random() * 100 + 100);
                            SendCmd sendCmd = serialPortServiceImp.lnSendCmd(port, "platform", cmdIdLn, Constant.LNCMDTYPE_CONTRL, 105, Arrays.asList("1"), "police", false);
                            sendCmd.setCallback(true);
                            sendCmd.setCallbackPlatForm(false);
                            sendQueue.offer(sendCmd);
                            SendCmd sendCmdaa = serialPortServiceImp.lnSendCmd(port, "platform", cmdIdLn, Constant.LNCMDTYPE_CONTRL, 5, Arrays.asList("1"), "police", false);
                            sendQueue.offer(sendCmdaa);
                        }
                    });
                    long dataPer = vertx.setPeriodic(1000 * 15 * 60, h -> {
                        if(lineStatus) {
                            int cmdIdLn = (int) (Math.random() * 100 + 100);
                            SendCmd sendCmd = serialPortServiceImp.lnSendCmd(port, "platform", cmdIdLn, Constant.LNCMDTYPE_CONTRL, 105, Arrays.asList("1"), "data", true);
                            sendCmd.setCallbackPlatForm(false);
                            sendCmd.setCallback(true);
                            sendQueue.offer(sendCmd);
                            SendCmd sendCmdbb = serialPortServiceImp.lnSendCmd(port, "platform", cmdIdLn, Constant.LNCMDTYPE_CONTRL, 5, Arrays.asList("1"), "data", false);
                            sendQueue.offer(sendCmdbb);
                        }
                    });
                    timerMap.get(netSocket.writeHandlerID()).add(policePer);
                    timerMap.get(netSocket.writeHandlerID()).add(dataPer);
                }

            });
            serverListen(server, redis, "mod_" + port);
        } catch (Exception e) {
            PublicUtils.printException(e, port);
        }

    }

    @Override
    public void stop() {
        logger.info("Collector client LnBreakerServer undeployed!!!" + "==>port:" + port + "==>");
    }

    class DetectorServer implements Handler<Buffer> {
        Map<String, Long> keepLiveMap;
        NetSocket netSocket;
        PriorityBlockingQueue<SendCmd> sendQueue;
        ConcurrentLinkedQueue<CallBackCmd> returnQueue;



        public DetectorServer(NetSocket netSocket, Map<String, Long> keepLiveMap, PriorityBlockingQueue<SendCmd> sendQueue, ConcurrentLinkedQueue<CallBackCmd> returnQueue) {
            this.keepLiveMap = keepLiveMap;
            this.netSocket = netSocket;
            this.sendQueue = sendQueue;
            this.returnQueue = returnQueue;
        }

        private Buffer preData = Buffer.buffer();
        private Map<String, byte[]> prebytes = new ConcurrentHashMap(16);

        private byte preDataBytes[] = new byte[]{(byte) 0xAA, (byte) 0xAA};
        private byte tailDataBytes[] = new byte[]{0x55, 0x55};

        volatile boolean isSave=true;

        @Override
        public void handle(Buffer buffer) {
            try {
                keepLiveMap.put("alive", System.currentTimeMillis());
                byte[] bytes = preData.appendBuffer(buffer).getBytes();
                logger.info("port:{}==>receive data:{}",port,Utils.bytes2String(buffer.getBytes()));
                preData=parseCan(bytes, preData, prebytes, preDataBytes, tailDataBytes, (b) -> {
                    parseData(b);
                });
//                logger.debug(Utils.bytes2String(preData.getBytes()));
            } catch (Exception e) {
                PublicUtils.printException(e, port);
            }
        }

        private void parseData(byte[] datas) {
            logger.info("port:{}==>parse data:{}", port, Utils.bytes2String(datas));
            int dataLen = datas.length;
            byte[] rawData = Arrays.copyOfRange(datas, 3, datas.length - 2);
            byte[] crcData = Arrays.copyOfRange(datas, 2, 3);
            if (!CRC16.calcSumCheck(rawData, crcData)) {
                logger.warn("port:{}==>check crc no pass==>rawData:{}==>crcData:{}==>data:{}", port, Utils.bytes2String(rawData), Utils.bytes2String(crcData), Utils.bytes2String(datas));
                return;
            }
            String cmdCallkey = Utils.bytes2String(datas, 3, 4);
            CallBackCmd ele = pollCallBackCmd(cmdCallkey, returnQueue);
            if (ele != null) {
                isSave = ele.isSave();
            } else {
                isSave = true;
            }
            Integer readWrite = getValueBytype(datas, 5);
            String deviceId = getValueBytype(datas, 3,2,String.class);
            List<BulkOperation> bulkOperationList = new ArrayList<>();
            JsonArray lasteData = new JsonArray();
            JsonArray policeData = new JsonArray();
            JsonArray alarmeData = new JsonArray();

            if (readWrite == 1) {
                if (dataLen==138) {
                    int pointer = 6;
                    int model = getValueBytype(datas, pointer += 2, 2, Integer.class);
                    int temperatureCount = model & 0x0F;
                    int electricleakageCount = model >> 4 & 0x0F;
                    int policeFlag = getValueBytype(datas, pointer += 2, 2);
                    int alarmFlag = getValueBytype(datas, pointer += 2, 2);
                    int electricleakagepoliceValue = getValueBytype(datas, pointer += 2, 2);
                    int temperature1policeValue = getValueBytype(datas, pointer += 2, 2);
                    int temperature2policeValue = getValueBytype(datas, pointer += 2, 2);
                    int temperature3policeValue = getValueBytype(datas, pointer += 2, 2);
                    int temperature4policeValue = getValueBytype(datas, pointer += 2, 2);
                    isPoliceTempAndleank(policeData, policeFlag, electricleakagepoliceValue, temperature1policeValue, temperature2policeValue, temperature3policeValue, temperature4policeValue);
                    isPoliceTempAndleank(alarmeData, alarmFlag);

                    int electricleakageValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electricleakageValue, 63);
                    int temperature1Value = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, temperature1Value, 5);
                    int temperature2Value = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, temperature2Value, 6);
                    int temperature3Value = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, temperature3Value, 7);
                    int temperature4Value = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, temperature4Value, 8);
                    int electriccurrentAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electriccurrentAValue, 12);
                    int electriccurrentBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electriccurrentBValue, 13);

                    int electriccurrentCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electriccurrentCValue, 14);

                    int voltageAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltageAValue, 9);

                    int voltageBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltageBValue, 10);

                    int voltageCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltageCValue, 11);

                    int policevoltageFlag = getValueBytype(datas, pointer += 2, 2);
                    isPoliceVoltage(alarmeData, policevoltageFlag);

                    int electriccurrentApoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int electriccurrentBpoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int electriccurrentCpoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int voltageApoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int voltageBpoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int voltageCpoliceValue = getValueBytype(datas, pointer += 2, 2);


                    int electricquantityAValue = getValueBytype(datas, pointer += 4, 4);
                    saveMongoJson(bulkOperationList, lasteData, electricquantityAValue, 1);

                    int electricquantityBValue = getValueBytype(datas, pointer += 4, 4);
                    saveMongoJson(bulkOperationList, lasteData, electricquantityBValue, 2);

                    int electricquantityCValue = getValueBytype(datas, pointer += 4, 4);
                    saveMongoJson(bulkOperationList, lasteData, electricquantityCValue, 3);

                    int apparentLoadAValue = getValueBytype(datas, pointer += 4, 4);
                    saveMongoJson(bulkOperationList, lasteData, apparentLoadAValue, 20);

                    int apparentLoadBValue = getValueBytype(datas, pointer += 4, 4);
                    saveMongoJson(bulkOperationList, lasteData, apparentLoadBValue, 16);

                    int apparentLoadCValue = getValueBytype(datas, pointer += 4, 4);
                    saveMongoJson(bulkOperationList, lasteData, apparentLoadCValue, 17);

                    int factorAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, factorAValue, 18);

                    int factorBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, factorBValue, 21);

                    int factorCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, factorCValue, 22);

                    int frequencyAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, frequencyAValue, 208);

                    int frequencyBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, frequencyBValue, 209);

                    int frequencyCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, frequencyCValue, 210);

                    int otherpolice = getValueBytype(datas, pointer += 2, 2);
                    isPoliceotherpolice(policeData, alarmeData, otherpolice);
                    int electricarcpoliceAValue = getValueBytype(datas, pointer += 2, 2);

                    int electricarcpoliceBValue = getValueBytype(datas, pointer += 2, 2);

                    int electricarcpoliceCValue = getValueBytype(datas, pointer += 2, 2);

                    int electricarcAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electricarcAValue, 211);

                    int electricarcBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electricarcBValue, 212);

                    int electricarcCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, electricarcCValue, 213);

                    int voltageBalanceValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltageBalanceValue, 24);

                    int voltageBalancepoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int currentBalanceValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, currentBalanceValue, 25);

                    int currentBalancepoliceValue = getValueBytype(datas, pointer += 2, 2);

                    int single = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, single, 200);

                    int voltagePhaseAngleAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltagePhaseAngleAValue, 214);

                    int voltagePhaseAngleBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltagePhaseAngleBValue, 215);

                    int voltagePhaseAngleCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, voltagePhaseAngleCValue, 216);

                    int currentPhaseAngleAValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, currentPhaseAngleAValue, 217);

                    int currentPhaseAngleBValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, currentPhaseAngleBValue, 218);

                    int currentPhaseAngleCValue = getValueBytype(datas, pointer += 2, 2);
                    saveMongoJson(bulkOperationList, lasteData, currentPhaseAngleCValue, 219);
                    int bigPoliceValue = getValueBytype(datas, pointer, 4);

                    if (!bulkOperationList.isEmpty()) {
                        if (isSave) {
                            saveMongoAndSend(Constant.MONGONAME_REAL, mongoClient, bulkOperationList, eventBus, lasteData);
                        }
                    }

                    if (!policeData.isEmpty()) {
                        eventBus.send(Constant.MOD_DEVICE_POLICE, returnResult(policeData));
                    }

                    if (!alarmeData.isEmpty()) {
                        eventBus.send(Constant.MOD_DEVICE_FAIL, returnResult(alarmeData));
                    }
                }else {
                    logger.info(Utils.bytes2String(datas));
                }
            } else if (readWrite == 2) {
                if (ele != null) {
                    ele.setStatus(0);
                    ele.setSuccess(true);
                    ele.setCallBackCmd(Utils.bytes2String(datas));
                    eventBus.send(Constant.MOD_CALLBACK, returnResult(JsonObject.mapFrom(ele)));
                }
            } else {
                logger.warn("port:{}==>check readWrite no pass==>==>data:{}", port, Utils.bytes2String(datas));

            }
        }
        private void isPoliceTempAndleank(JsonArray policeDate, int policeFlag, Object electricleakagepoliceValue, Object temperature1policeValue, Object temperature2policeValue, Object temperature3policeValue, Object temperature4policeValue) {
            if (isPolice(policeFlag,BINARY_1)){
                getPolice(policeDate, 63, electricleakagepoliceValue);
            }
            if (isPolice(policeFlag,BINARY_2)){
                getPolice(policeDate, 5, temperature1policeValue);
            }
            if (isPolice(policeFlag,BINARY_3)){
                getPolice(policeDate, 6, temperature2policeValue);
            }
            if (isPolice(policeFlag,BINARY_4)){
                getPolice(policeDate, 7, temperature3policeValue);
            }
            if (isPolice(policeFlag,BINARY_5)){
                getPolice(policeDate, 8, temperature4policeValue);
            }
        }

        private void isPoliceTempAndleank(JsonArray policeDate, int policeFlag) {
            isPoliceandSet(policeDate, policeFlag, BINARY_1, 363);
            isPoliceandSet(policeDate, policeFlag, BINARY_2, 315);
            isPoliceandSet(policeDate, policeFlag, BINARY_3, 316);
            isPoliceandSet(policeDate, policeFlag, BINARY_4, 317);
            isPoliceandSet(policeDate, policeFlag, BINARY_5, 318);
        }

        private void isPoliceotherpolice(JsonArray policeData,JsonArray alarmData, int policeFlag) {
            isPoliceandSet(alarmData, policeFlag, BINARY_1, 409);
            isPoliceandSet(alarmData, policeFlag, BINARY_2, 410);
            isPoliceandSet(alarmData, policeFlag, BINARY_3, 411);

            isPoliceandSet(policeData, policeFlag, BINARY_4, 292);
            isPoliceandSet(policeData, policeFlag, BINARY_5, 293);
            isPoliceandSet(policeData, policeFlag, BINARY_6, 294);

            isPoliceandSet(policeData, policeFlag, BINARY_7, 24);
            isPoliceandSet(policeData, policeFlag, BINARY_8, 25);

            isPoliceandSet(policeData, policeFlag, BINARY_9, 421);

            isPoliceandSet(policeData, policeFlag, BINARY_10, 152);
            isPoliceandSet(policeData, policeFlag, BINARY_11, 153);
            isPoliceandSet(policeData, policeFlag, BINARY_12, 154);

            isPoliceandSet(policeData, policeFlag, BINARY_13, 422);
        }

        private void isPoliceVoltage(JsonArray policeDate, int policeFlag) {
            isPoliceandSet(policeDate, policeFlag, BINARY_1, 155);
            isPoliceandSet(policeDate, policeFlag, BINARY_2, 156);
            isPoliceandSet(policeDate, policeFlag, BINARY_3, 157);

            isPoliceandSet(policeDate, policeFlag, BINARY_4, 400);
            isPoliceandSet(policeDate, policeFlag, BINARY_5, 401);
            isPoliceandSet(policeDate, policeFlag, BINARY_6, 402);

            isPoliceandSet(policeDate, policeFlag, BINARY_7, 403);
            isPoliceandSet(policeDate, policeFlag, BINARY_8, 404);
            isPoliceandSet(policeDate, policeFlag, BINARY_9, 405);

            isPoliceandSet(policeDate, policeFlag, BINARY_10, 406);
            isPoliceandSet(policeDate, policeFlag, BINARY_11, 407);
            isPoliceandSet(policeDate, policeFlag, BINARY_12, 408);

            isPoliceandSet(policeDate, policeFlag, BINARY_13, 308);
            isPoliceandSet(policeDate, policeFlag, BINARY_14, 308);
            isPoliceandSet(policeDate, policeFlag, BINARY_15, 308);

        }

        private void isPoliceandSet(JsonArray policeDate, int policeFlag, int binary1, int i) {
            if (isPolice(policeFlag, binary1)) {
                getPolice(policeDate, i);
            }
        }
    }

    class LnBreakerServer implements Handler<Buffer> {
        Map<String, Long> keepLiveMap;
        NetSocket netSocket;
        PriorityBlockingQueue<SendCmd> sendQueue;
        ConcurrentLinkedQueue<CallBackCmd> returnQueue;

        public LnBreakerServer(NetSocket netSocket, Map<String, Long> keepLiveMap, PriorityBlockingQueue<SendCmd> sendQueue, ConcurrentLinkedQueue<CallBackCmd> returnQueue) {
            this.keepLiveMap = keepLiveMap;
            this.netSocket = netSocket;
            this.sendQueue = sendQueue;
            this.returnQueue = returnQueue;
        }

         String subData = "";
         volatile boolean isSave=true;

        @Override
        public void handle(Buffer buffer) {
            keepLiveMap.put("alive", System.currentTimeMillis());
            String d = buffer.toString().replaceAll("(\\s*|\t|\r|\n)", "").toUpperCase();
            logger.info("receive data ==>port:{}==>HandlerID:{}==>datas:{}" , port, netSocket.writeHandlerID(),d);
            if(!d.startsWith("DC")||!d.endsWith("7573")){
                logger.info(buffer.toString());
            }
            String datas = Joiner.on("").join(subData, d);
            subData=parseDataStr(datas,12,4,(da)->{
                parseData(da);
            });

        }

        private void parseData(String datas) {
            try {

                int totalLength = datas.length() / 2;
                String handlerId = netSocket.writeHandlerID();
//                logger.info("receive data ==>port:{}==>HandlerID:{}==>" + datas, port, handlerId);
                int frame_Type = getValueBytype(datas, 20, 4, int.class);
                String cmd_Id = getValueBytype(datas, 24, 4, String.class);
                int cmdId = Integer.parseInt(cmd_Id,16);
                String dataStr = datas.substring(36, totalLength * 2 - 3 * 2);
                String data = StrUtils.decode(Constant.secretkeys.get("6161"), dataStr).toUpperCase();

                CallBackCmd ele = pollCallBackCmd(StrUtils.getSmall(cmd_Id),returnQueue);
                if (ele!=null){
                    isSave= ele.isSave();
                }else {
                    isSave=true;
                }

                List<BulkOperation> bulkOperationList = new ArrayList<>();
                JsonArray lasteDate = new JsonArray();

                int pointer = 0;
                JsonObject entity = new JsonObject();

                if (frame_Type == 4) {

                    pointer = getBase_Id(data, pointer, entity);
                    int CI_Lock = getValueBytype(data, pointer, 2, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI_Lock, 206);//TODO 是否锁死机构
                    pointer += 2;
                    int CI_Switch = getValueBytype(data, pointer, 2, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI_Switch, 205);//开关状态
                    if (ele != null) {
                        if (cmdId <= 300 && cmdId >= 200) {
                            ele.setStatus(CI_Switch);
                            ele.setSuccess(true);
                            eventBus.send(Constant.MOD_CALLBACK, returnResult(JsonObject.mapFrom(ele)));
                        }
                    }

                    pointer += 2;
                    int CI_Signal = getValueBytype(data, pointer, 2, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI_Signal, 200);//信号强度
                    pointer += 2;
                    int CI_Warn = getValueBytype(data, pointer, 8, int.class);

                    JsonArray policeDate = new JsonArray();

                    if ((CI_Warn & 0x8) == 0x8) {
                        getPolice(entity, policeDate, 264);//TODO 漏保自检后自动合闸
                    }
                    if ((CI_Warn & 0x10) == 0x10) {
                        getPolice(entity, policeDate, 215);//TODO 温度N报警，暂时认为是开关温度报警
                    }
                    if ((CI_Warn & 0x20) == 0x20) {
                        //TODO 温度N脱扣
                    }
                    if ((CI_Warn & 0x40) == 0x40) {
                        getPolice(entity, policeDate, 63);//漏电报警
                    }
                    if ((CI_Warn & 0x80) == 0x80) {
                        //TODO 漏电脱扣
                    }
                    if ((CI_Warn & 0x100) == 0x100) {
                        getPolice(entity, policeDate, 265);//TODO 剩余电量报警
                    }
                    if ((CI_Warn & 0x200) == 0x200) {
                        //TODO 剩余电量脱扣
                    }
                    if ((CI_Warn & 0x400) == 0x400) {
                        getPolice(entity, policeDate, 24);//电压平衡度报警（电压不平衡报警）
                    }
                    if ((CI_Warn & 0x800) == 0x800) {
                        //TODO 电压平衡度脱扣（电压不平衡脱扣）
                    }
                    if ((CI_Warn & 0x1000) == 0x1000) {
                        getPolice(entity, policeDate, 25);//电流平衡度报警（电流不平衡报警）
                    }
                    if ((CI_Warn & 0x2000) == 0x2000) {
                        //TODO 电流平衡度脱扣（电流不平衡脱扣）
                    }
                    if ((CI_Warn & 0x1000000) == 0x1000000) {
                        getPolice(entity, policeDate, 266);//TODO 手动合闸报警
                    }
                    if ((CI_Warn & 0x2000000) == 0x2000000) {
                        getPolice(entity, policeDate, 267);//TODO 手动关闸报警
                    }
                    if ((CI_Warn & 0x4000000) == 0x4000000) {
                        getPolice(entity, policeDate, 268);//TODO 短路跳闸
                    }
                    if ((CI_Warn & 0x10000000) == 0x10000000) {
                        getPolice(entity, policeDate, 269);//TODO 本地按钮漏电自检
                    }
                    if ((CI_Warn & 0x40000000) == 0x40000000) {
                        getPolice(entity, policeDate, 270);//TODO 远程漏电自检
                    }

                    //TODO 告警类型：基本错误
                    pointer += 8;
                    int CI__PowerP = getValueBytype(data, pointer, 8, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI__PowerP, 207);//TODO 剩余电量
                    pointer += 8;

                    pointer = getDeviceInfo(data, pointer, 0, bulkOperationList, lasteDate, policeDate, entity);
                    int CI_N_Tem = getValueBytype(data, pointer, 4, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI_N_Tem, 121);//TODO 温度，暂时认为是开关温度
                    pointer += 4;
                    int CI__Leakage = getValueBytype(data, pointer, 4, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI__Leakage, 63);//TODO 当前漏电值，暂时认为是剩余电流
                    pointer += 4;
                    pointer = getDeviceInfo(data, pointer, 1, bulkOperationList, lasteDate, policeDate, entity);
                    pointer = getDeviceInfo(data, pointer, 2, bulkOperationList, lasteDate, policeDate, entity);
                    int CI_C_Volb = getValueBytype(data, pointer, 2, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI_C_Volb, 226);//TODO 电压平衡度，暂时认为是开关电压平衡度
                    pointer += 2;
                    int CI_C_Eleb = getValueBytype(data, pointer, 2, int.class);
                    saveMongoJson(bulkOperationList, lasteDate, entity, CI_C_Eleb, 227);//TODO 电流平衡度，暂时认为是开关电流平衡度
                    pointer += 2;

                    if (!policeDate.isEmpty()) {
                        eventBus.send(Constant.MOD_DEVICE_POLICE, returnResult(policeDate));
                    }

                    if (!bulkOperationList.isEmpty()) {
                        if (isSave) {
                            saveMongoAndSend(Constant.MONGONAME_REAL, mongoClient, bulkOperationList, eventBus, lasteDate);
                        }
                    }


                } else if (frame_Type == 5) {
                    pointer = getBase_Id(data, pointer, entity);
                    int Cfg_CI_Warn_Time  = getValueBytype(data, pointer, 1, int.class);
                    int Cfg_CI_Releas_Time  = getValueBytype(data, pointer, 1, int.class);
                    int Cfg_CI_Twice_Warn_Time  = getValueBytype(data, pointer, 2, int.class);
                    int Cfg_CI_Twice_Releas_Time  = getValueBytype(data, pointer, 2, int.class);


                }else if (frame_Type == 6) {
                    pointer = getBase_Id(data, pointer, entity);
                    int CC_Ctrl = getValueBytype(data, pointer, 8, int.class);
                    pointer += 8;
                    int CC_Ctrl_Value1 = getValueBytype(data, pointer, 8, int.class);
                    pointer += 8;
                    int CC_Ctrl_Value2 = getValueBytype(data, pointer, 8, int.class);
                    pointer += 8;
                    int CC_Ctrl_Value3 = getValueBytype(data, pointer, 8, int.class);
                    pointer += 8;
                    String CC_McuId = getSubstring(data, pointer, 24);
                    pointer += 24;
                    logger.info(cmd_Id + "fail-----------------------------------------------------");
                }

            } catch (Exception e) {
                PublicUtils.printException(e, port);
            }
        }


        private int getBase_Id(String data, int pointer, JsonObject entity) {
            int Base_Id_len = getValueBytype(data, pointer, 2, int.class);
            pointer += 2;
            List<String> Base_Id = new ArrayList<>();
            for (int i = 0; i < Base_Id_len; i++) {
                Base_Id.add(i, getValueBytype(data, pointer, 2, String.class));
                pointer += 2;
            }
            entity.put("deviceId", Base_Id.get(0));
            int Base_StateType_len = getValueBytype(data, pointer, 2, int.class);
            pointer = pointer + 2;
            List<String> Base_StateType = new ArrayList<>();
            for (int i = 0; i < Base_StateType_len; i++) {
                Base_StateType.add(i, getValueBytype(data, pointer, 4, String.class));
                pointer += 4;
            }
            return pointer;
        }

        //xiang:0,1,2代表A/B/C
        private int getDeviceInfo(String data,
                                  int pointer,
                                  int xiang,
                                  List<BulkOperation> bulkOperationList,
                                  JsonArray lasteDate,
                                  JsonArray policeDate,
                                  JsonObject entity) {
            int Warn__Releas = (Integer) getValueBytype(data, pointer, 8, Integer.class);
            if (isPolice(Warn__Releas, 0x1)) {
                getPolice(entity, policeDate, (9 + xiang) * 10 + 1);//过压报警
            }
            if (isPolice(Warn__Releas, 0x2)) {
                //TODO 过压脱扣
            }
            if (isPolice(Warn__Releas, 0x4)) {
                getPolice(entity, policeDate, (9 + xiang) * 10 + 2);//欠压报警
            }
            if (isPolice(Warn__Releas, 0x8)) {
                //TODO 欠压脱扣
            }
            if (isPolice(Warn__Releas, 0x10)) {
                getPolice(entity, policeDate, 130 + xiang);//温度报警
            }
            if (isPolice(Warn__Releas, 0x20)) {
                //TODO 温度脱扣
            }
            if (isPolice(Warn__Releas, 0x40)) {
                getPolice(entity, policeDate, 12 + xiang);//电流报警
            }
            if (isPolice(Warn__Releas, 0x80)) {
                //TODO 电流脱扣
            }
            if (isPolice(Warn__Releas, 0x100)) {
                getPolice(entity, policeDate, 271 + xiang);//TODO 电压突变报警
            }
            if (isPolice(Warn__Releas, 0x200)) {
                //TODO 电压突变脱扣
            }
            if (isPolice(Warn__Releas, 0x400)) {
                getPolice(entity, policeDate, 274 + xiang);//TODO 电流突变报警
            }
            if (isPolice(Warn__Releas, 0x800)) {
                //TODO 电流突变脱扣
            }
            if (isPolice(Warn__Releas, 0x1000)) {
                getPolice(entity, policeDate, 277 + xiang);//TODO 电压相位角报警
            }
            if (isPolice(Warn__Releas, 0x2000)) {
                //TODO 电压相位角脱扣
            }
            if (isPolice(Warn__Releas, 0x4000)) {
                getPolice(entity, policeDate, 280 + xiang);//TODO 恶性负载报警
            }
            if (isPolice(Warn__Releas, 0x8000)) {
                //TODO 恶性负载脱扣
            }
            if (isPolice(Warn__Releas, 0x10000)) {
                getPolice(entity, policeDate, 283 + xiang);//TODO 视在功率报警
            }
            if (isPolice(Warn__Releas, 0x20000)) {
                //TODO 视在功率脱扣
            }
            if (isPolice(Warn__Releas, 0x40000)) {
                getPolice(entity, policeDate, 286 + xiang);//TODO 有功功率报警
            }
            if (isPolice(Warn__Releas, 0x80000)) {
                //TODO 有功功率脱扣
            }
            if (isPolice(Warn__Releas, 0x100000)) {
                getPolice(entity, policeDate, 289 + xiang);//TODO 无功功率报警
            }
            if (isPolice(Warn__Releas, 0x200000)) {
                //TODO 无功功率脱扣
            }
            if (isPolice(Warn__Releas, 0x400000)) {
                getPolice(entity, policeDate, 292 + xiang);//TODO 电弧报警
            }
            if (isPolice(Warn__Releas, 0x800000)) {
                //TODO 电弧脱扣
            }
            if (isPolice(Warn__Releas, 0x1000000)) {
                getPolice(entity, policeDate, 295 + xiang);//TODO 功率因数报警
            }
            if (isPolice(Warn__Releas, 0x2000000)) {
                //TODO 功率因数脱扣
            }
            if (isPolice(Warn__Releas, 0x4000000)) {
                getPolice(entity, policeDate, 298 + xiang);//TODO 如果因为欠压脱扣电压恢复正常自动合闸
            }
            if (isPolice(Warn__Releas, 0x8000000)) {
                getPolice(entity, policeDate, 301 + xiang);//TODO 如果因为过压脱扣电压恢复正常自动合闸
            }

            pointer += 8;
            int Power = getValueBytype(data, pointer, 8, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Power,4);//TODO 总用电量是总正相有功电能吗
            pointer += 8;
            int Hz = getValueBytype(data, pointer, 2, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Hz, 208 + xiang);//TODO A/B/C相电压频率
            pointer += 2;
            int Power_Factor = getValueBytype(data, pointer, 2, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Power_Factor, 20 + xiang);//A/B/C相功率因数
            pointer += 2;
            int Tem = getValueBytype(data, pointer, 4, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Tem, 130 + xiang);//A/B/C相温度
            pointer += 4;
            int Vol = getValueBytype(data, pointer, 8, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Vol, 9 + xiang);//A/B/C相电压
            pointer += 8;
            int Vol_Min_Warn = getValueBytype(data, pointer, 4, int.class);

            pointer += 4;
            int Vol_Min_Releas = getValueBytype(data, pointer, 4, int.class);
            //TODO 告警类型：欠压脱扣值
            pointer += 4;
            int Vol_Max_Warn = getValueBytype(data, pointer, 4, int.class);
            //TODO 告警类型：过压报警值
            pointer += 4;
            int Vol_Max_Releas = getValueBytype(data, pointer, 4, int.class);
            //TODO 告警类型：过压脱扣值
            pointer += 4;
            int Vol_Mutation_Warn = getValueBytype(data, pointer, 4, int.class);
            //TODO 告警类型：电压突变报警值
            pointer += 4;
            int Vol_Mutation_Releas = getValueBytype(data, pointer, 4, int.class);
            //TODO 告警类型：电压突变脱扣值
            pointer += 4;
            int Ele = getValueBytype(data, pointer, 8, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Ele, 12 + xiang);//A/B/C相电流
            pointer += 8;
            int Ele_Warn = getValueBytype(data, pointer, 8, int.class);
            //TODO 告警类型：电流报警值
            pointer += 8;
            int Ele_Releas = getValueBytype(data, pointer, 8, int.class);
            //TODO 告警类型：电流脱扣值
            pointer += 8;
            int Ele_Mutation_Warn = getValueBytype(data, pointer, 8, int.class);
            //TODO 告警类型：电流突变报警值
            pointer += 8;
            int Ele_Mutation_Releas = getValueBytype(data, pointer, 8, int.class);
            //TODO 告警类型：电流突变脱扣值
            pointer += 8;
            int Arc = getValueBytype(data, pointer, 2, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Arc, 211 + xiang);//TODO A/B/C相故障电弧数量
            pointer += 2;
            int Vol_Angel = getValueBytype(data, pointer, 2, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Vol_Angel, 214 + xiang);//TODO A/B/C相电压相位角
            pointer += 2;
            int Angel = getValueBytype(data, pointer, 2, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Angel, 217 + xiang);//TODO A/B/C相电流相位角
            pointer += 2;
            int Mg = getValueBytype(data, pointer, 4, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Mg, 220 + xiang);//TODO A/B/C相恶性负载
            pointer += 4;
            int App = getValueBytype(data, pointer, 4, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, App, 223 + xiang);//TODO A/B/C相视在功率
            pointer += 4;
            int Ap = getValueBytype(data, pointer, 4, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Ap, 16 + xiang);//A/B/C相有功功率
            pointer += 4;
            int Rp = getValueBytype(data, pointer, 4, int.class);
            saveMongoJson(bulkOperationList, lasteDate, entity, Rp, 26 + xiang);//A/B/C相无功功率
            pointer += 4;
            return pointer;
        }


        private byte[] getBytes(byte[] bytes, int i, int j) {
            byte[] byteArray = Utils.getbytes(bytes, i, j);
            return getSmall(byteArray);
        }

        private byte[] decode(int[] ints, byte[] dataBytes) {
            byte[] data = getDecode(ints, dataBytes);
            return data;
        }

        private byte[] getSmall(byte[] data) {
            int length = data.length;
            for (int i = 0; i < length / 2; i++) {
                byte b = data[i];
                data[i] = data[length - 1 - i];
                data[length - 1 - i] = b;
            }
            return data;
        }

        private String getDecodeStr(int[] key, byte[] data) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; i++) {
                int res = data[i] & 0x00ff ^ key[i % 5];
                sb.append(String.format("%02x", res));
            }
            return sb.toString();
        }

        private byte[] getDecode(int[] key, byte[] data) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; i++) {
                int res = data[i] & 0x00ff ^ key[i % 5];
                data[i] = (byte) (res & 0xff);
            }
            return data;
        }


        public byte[] getByteArray(String data) {
            byte[] bytes = data.getBytes();
            int l = bytes.length;
            byte[] result = new byte[l / 2];
            for (int i = 0, j = 0; i < l; i += 2, j++) {
                byte a = Byte.decode("0x" + new String(new byte[]{bytes[i]})).byteValue();
                byte b = Byte.decode("0x" + new String(new byte[]{bytes[i + 1]})).byteValue();
                result[j] = (byte) (((a << 4) & 0xf0) | (b & 0x0f));
            }
            return result;
        }
    }

}
